package com.googlecode.openrtp.grizzly.rtcp.filter;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.inject.Inject;
import org.glassfish.grizzly.Buffer;
import org.glassfish.grizzly.filterchain.BaseFilter;
import org.glassfish.grizzly.filterchain.FilterChainContext;
import org.glassfish.grizzly.filterchain.NextAction;
import com.googlecode.openrtp.grizzly.util.BufferUtil;
import com.googlecode.openrtp.spi.rtcp.RtcpHeaderPacket;
import com.googlecode.openrtp.spi.rtcp.RtcpSourceDescriptionPacket;
import com.googlecode.openrtp.spi.rtcp.SourceDescription;
import com.googlecode.openrtp.spi.rtcp.SourceDescriptionType;

/**
 *
 * @author jocke
 */
public class RtcpSourceDescriptionFilter extends BaseFilter {

    private BufferUtil bufferUtil;
    private static final Logger LOG = Logger.getLogger(RtcpSourceDescriptionFilter.class.getName());

    @Inject
    public RtcpSourceDescriptionFilter(BufferUtil bufferUtil) {
        this.bufferUtil = bufferUtil;
    }

    @Override
    public NextAction handleRead(FilterChainContext ctx) throws IOException {

        Buffer sourceBuffer = ctx.getMessage();

        RtcpHeaderPacket headerPacket = (RtcpHeaderPacket) ctx.getAttributes().getAttribute(RtcpHeaderPacket.class.getName());

        ByteBuffer longBuffer = bufferUtil.allocate(ctx, 8);

        Map<Long, SourceDescription> items = new HashMap<>();

        for (int i = 0; i < headerPacket.getRc(); i++) {

            long ssrc = bufferUtil.getUnsignedIntAsLong(sourceBuffer, longBuffer);
            Map<SourceDescriptionType, String> desc = new EnumMap<>(SourceDescriptionType.class);
            
            while (sourceBuffer.hasRemaining()) {

                SourceDescriptionType type = SourceDescriptionType.fromByte(sourceBuffer.get());

                if (type == SourceDescriptionType.END) {
                    break;

                } else {
                    desc.put(type, bufferUtil.readString(sourceBuffer, sourceBuffer.get()));
                }
            }

            items.put(ssrc, SourceDescription.fromMap(desc));

            bufferUtil.seekBoundry(sourceBuffer);

        }

        LOG.log(Level.INFO, "Source description packet arrived items={0}", items);

        ctx.setMessage(RtcpSourceDescriptionPacket.create(headerPacket, items));

        return super.handleRead(ctx);

    }

    @Override
    public NextAction handleWrite(FilterChainContext ctx) throws IOException {

        Buffer sendBuffer = ctx.getMessage();

        RtcpSourceDescriptionPacket descriptionPacket = (RtcpSourceDescriptionPacket) ctx.getAttributes()
                .getAttribute(RtcpSourceDescriptionPacket.class.getName());

        Map<Long, SourceDescription> descs = descriptionPacket.getItems();

        for (Map.Entry<Long, SourceDescription> entry : descs.entrySet()) {

            sendBuffer.putInt(entry.getKey().intValue());
            Map<SourceDescriptionType, String> items = SourceDescription.toMap(entry.getValue());
            for (Map.Entry<SourceDescriptionType, String> desc : items.entrySet()) {
                sendBuffer.put((byte) desc.getKey().ordinal());
                byte[] bytes = desc.getValue().getBytes();
                sendBuffer.put((byte) bytes.length);
                sendBuffer.put(bytes);
            }

            bufferUtil.paddingToBoundry(sendBuffer);
        }

        return super.handleWrite(ctx);
    }
}
